{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Errors and Exceptions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "There are (at least) two distinguishable kinds of errors: syntax errors and exceptions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "invalid syntax (3511958662.py, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001B[0;36m  Cell \u001B[0;32mIn [1], line 1\u001B[0;36m\u001B[0m\n\u001B[0;31m    while True print('Hello world')\u001B[0m\n\u001B[0m               ^\u001B[0m\n\u001B[0;31mSyntaxError\u001B[0m\u001B[0;31m:\u001B[0m invalid syntax\n"
     ]
    }
   ],
   "source": [
    "while True print('Hello world')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Even if a statement or an expression is syntactically correct, it may cause an error when an attempt is made to execute it. Errors detected during execution are called `exceptions` and are not unconditionally fatal: you will soon learn how to handle them in Python programs. However, most exceptions are not handled by programs and result in error messages as shown here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "ename": "ZeroDivisionError",
     "evalue": "division by zero",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mZeroDivisionError\u001B[0m                         Traceback (most recent call last)",
      "Cell \u001B[0;32mIn [2], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;241;43m1\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m/\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\n",
      "\u001B[0;31mZeroDivisionError\u001B[0m: division by zero"
     ]
    }
   ],
   "source": [
    "1 / 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "can only concatenate str (not \"int\") to str",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mTypeError\u001B[0m                                 Traceback (most recent call last)",
      "Cell \u001B[0;32mIn [3], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m2\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m2\u001B[39;49m\n",
      "\u001B[0;31mTypeError\u001B[0m: can only concatenate str (not \"int\") to str"
     ]
    }
   ],
   "source": [
    "'2' + 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "ename": "IndexError",
     "evalue": "list index out of range",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mIndexError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[0;32mIn [4], line 2\u001B[0m\n\u001B[1;32m      1\u001B[0m x \u001B[38;5;241m=\u001B[39m [\u001B[38;5;241m1\u001B[39m,\u001B[38;5;241m2\u001B[39m,\u001B[38;5;241m3\u001B[39m]\n\u001B[0;32m----> 2\u001B[0m \u001B[43mx\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m4\u001B[39;49m\u001B[43m]\u001B[49m\n",
      "\u001B[0;31mIndexError\u001B[0m: list index out of range"
     ]
    }
   ],
   "source": [
    "x = [1,2,3]\n",
    "x[4]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### Handling exceptions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "imposible operation\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    1 / 0\n",
    "except ZeroDivisionError:\n",
    "    print('imposible operation')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "The `try` statement works as follows.\n",
    "\n",
    "- First, the `try` clause (the statement(s) between the `try` and `except` keywords) is executed.\n",
    "- If no exception occurs, the except clause is skipped and execution of the `try` statement is finished.\n",
    "- If an exception occurs during the execution of the `try` clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then the execution continues after the `try` statement.\n",
    "- If an exception occurs but does not match the exception named in the except clause, it is passed on to outer `try` statements; if no handler is found, it is an unhandled exception and the execution stops with a message as shown above.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "An except clause may name multiple exceptions as a parenthesized tuple, for example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    pass\n",
    "except (RuntimeError, TypeError, NameError):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    [1,2,3][4]\n",
    "except TypeError:\n",
    "    print(\"oops ham\")\n",
    "except ZeroDivisionError:\n",
    "    print(\"oops spam\")\n",
    "except:\n",
    "    print(\"Unexpected error!\")\n",
    "    raise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "The `try … except` statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "x = [1,2,3,4,0]\n",
    "for i in x:\n",
    "    try:\n",
    "        print(10 / i)\n",
    "    except ZeroDivisionError:\n",
    "        print('wrong operations')\n",
    "    else:\n",
    "        print('good operation')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    1 / 0\n",
    "except ZeroDivisionError:\n",
    "    print(1)\n",
    "except ZeroDivisionError:\n",
    "    print(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "The except clause may specify a variable after the exception name. The variable is bound to an exception instance with the arguments stored in instance.args."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    raise Exception('spam', 'eggs')\n",
    "except Exception as inst:\n",
    "    print(type(inst))    # the exception instance\n",
    "    print(inst.args)     # arguments stored in .args\n",
    "    print(inst)          # __str__ allows args to be printed directly,\n",
    "                         # but may be overridden in exception subclasses\n",
    "    x, y = inst.args     # unpack args\n",
    "    print('x =', x)\n",
    "    print('y =', y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Raise errors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "raise NameError('HiThere')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    raise NameError\n",
    "except NameError:\n",
    "    print('oops')\n",
    "    raise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "x = 0 # 1\n",
    "\n",
    "try:\n",
    "#     1/x\n",
    "    raise ValueError()\n",
    "except ZeroDivisionError:\n",
    "    print('handle')\n",
    "finally:\n",
    "    print('run anyway')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "If a finally clause is present, the finally clause will be executed as the last task before the try statement completes. The finally clause checks whether or not the try statement produces an exception. The following points explain some more complex cases when an exception occurs:\n",
    "\n",
    "- If an exception occurs during the execution of the `try` clause, the exception may be handled by an `except` clause. If the exception is not handled by an `except` clause, the exception is re-raised after the `finally` clause has been executed.\n",
    "- An exception could occur during the execution of an `except` or `else` clause. Again, the exception is re-raised after the `finally` clause has been executed.\n",
    "- If the `try` statement reaches a `break`, `continue` or `return` statement, the `finally` clause will be executed just prior to the `break`, `continue` or `return` statement’s execution.\n",
    "- If a `finally` clause includes a return statement, the `finally` clause’s return statement will be executed before, and instead of, the return statement in a try clause.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "def test():\n",
    "    try:\n",
    "        1/0\n",
    "    except ZeroDivisionError:\n",
    "        return 1\n",
    "    finally:\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "0"
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n",
     "is_executing": true
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}